package lt.egidijus.aatest.popup.actions;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UTFDataFormatException;
import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Semaphore;

import lt.egidijus.aatest.BrowserView;
import lt.egidijus.aatest.generator.TestSuiteGenerator;
import lt.egidijus.aatest.junit.JUnitFinder;
import lt.egidijus.aatest.listener.TestRunnerListener;
import lt.egidijus.aatest.model.AAtestClass;
import lt.egidijus.aatest.model.AAtestList;
import lt.egidijus.aatest.report.ReportGenerator;
import lt.egidijus.aatest.runner.AATestJunitLauncher;
import lt.egidijus.aatest.utils.Constants;
import lt.egidijus.aatest.utils.Utils;
import lt.egidijus.aatest.wizards.RunCustomTestsWizard;
import lt.egidijus.aatest.wizards.helpers.TestsWizardDialog;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.debug.core.Launch;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.core.JarPackageFragmentRoot;
import org.eclipse.jdt.internal.core.PackageFragment;
import org.eclipse.jdt.internal.core.PackageFragmentRoot;
import org.eclipse.jdt.internal.junit.launcher.JUnit4TestFinder;
import org.eclipse.jdt.junit.JUnitCore;
import org.eclipse.jdt.junit.launcher.JUnitLaunchShortcut;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.jdt.launching.IVMInstall;
import org.eclipse.jdt.launching.IVMInstall2;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.jdt.launching.sourcelookup.PackageFragmentRootSourceLocation;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.browser.TitleEvent;
import org.eclipse.swt.browser.TitleListener;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IActionDelegate;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.ISelectionService;
import org.eclipse.ui.IViewReference;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.console.ConsolePlugin;
import org.eclipse.ui.console.IConsole;
import org.eclipse.ui.console.IConsoleConstants;
import org.eclipse.ui.console.IConsoleManager;
import org.eclipse.ui.console.IConsoleView;
import org.eclipse.ui.console.MessageConsole;
import org.eclipse.ui.console.MessageConsoleStream;
import org.eclipse.ui.internal.Workbench;
import org.osgi.framework.Bundle;

public class CalculateCoverageAction  implements IObjectActionDelegate {

	/**
	 * Constructor for Action1.
	 */
	public CalculateCoverageAction() {
		super();
	}

	private Shell shell;

	/**
	 * @see IObjectActionDelegate#setActivePart(IAction, IWorkbenchPart)
	 */
	public void setActivePart(IAction action, IWorkbenchPart targetPart) {
		shell = targetPart.getSite().getShell();
	}

	String testType = "";
	String objectQName = "";
	String generationTime = "";

	/**
	 * @see IActionDelegate#run(IAction)
	 */
	public void run(IAction action) {
		
		if (!Constants.clickTestProject){
			Display.getDefault().asyncExec(new Runnable() {
				public void run() {
					MessageDialog.openError(shell, "Coverage error", "Coverage can generate only tests or package in test project!");
				}
			});
			return;
		}
		
		ProgressMonitorDialog dialog = new ProgressMonitorDialog(shell);
		try {
			dialog.run(true, true, new IRunnableWithProgress() {
				@Override
				public void run(IProgressMonitor monitor) {
					long t1 =  System.currentTimeMillis();
					monitor.beginTask("Generating coverage report..", 7);
					try{
						final String path = ResourcesPlugin.getWorkspace().getRoot().getLocation().toString();
						String updateMainProject = "android update project -p \"" + path +"/"+ Constants.projectName +"\"";
						String buildMainProject = "ant -f \"" + path +"/"+ Constants.projectName +"/build.xml\" clean debug";

						String updateProject = "android update test-project -m \"" + path +"/"+ Constants.projectName +"\" -p \"" + path +"/"+ Constants.testProjectName +"\"";
						String buildCoverageReport = "ant -f \"" + path +"/"+ Constants.testProjectName +"/build.xml\" all clean emma debug install test-one";
						String buildXMLReport = "java emma report -r xml -in \"" + path +"/"+ Constants.testProjectName +"/coverage/coverage.em\" -in \"" 
						+ path +"/"+ Constants.testProjectName +"/coverage/coverage.ec\"" + " -Dreport.xml.out.file=\""+path +"/"+ Constants.testProjectName +"/coverage/coverage.xml\"";

						monitor.subTask("Initialization..");
						monitor.worked(1);
						//String komanda = "ping google.com";
				        System.out.println(updateMainProject);
				        System.out.println(buildMainProject);
				       System.out.println(buildXMLReport);
				        System.out.println(updateProject);
				        System.out.println(buildCoverageReport);
				       System.out.println(buildXMLReport);
				        MessageConsole myConsole = findConsole("Coverage"); 
				        MessageConsoleStream out = myConsole.newMessageStream();
				        myConsole.activate();
						monitor.subTask("Update main project..");
				        boolean exitVal = commandLine(updateMainProject, out, monitor);
						monitor.worked(2);
//				        if (exitVal){
//							monitor.subTask("Build main project..");
//				        	exitVal = commandLine(buildMainProject, out, monitor);
//							monitor.worked(3);
//				        }
				        if (exitVal){
							monitor.subTask("Updating test project..");
				        	exitVal = commandLine(updateProject, out, monitor);
							monitor.worked(3);
				        }
						Utils.setTestToCoverage(testType, objectQName);
				        if (exitVal){
							monitor.subTask("Building test project, running tests and generating report..");
				        	exitVal = commandLine(buildCoverageReport, out, monitor);
							monitor.worked(4);
				        }
				     //   if (exitVal){
					//		monitor.subTask("Generating xml report..");
				    //    	exitVal = commandLine(buildXMLReport, out, monitor);
					//		monitor.worked(4);
				   //     }
					//	boolean exitVal = true;
				        System.out.println("exitVal " +exitVal); 
				        monitor.done();
				        long t2 =  System.currentTimeMillis();
				        generationTime = String.format("\nExecution time -%8.2f s.", (t2 - t1)/1000.0);
				        if (exitVal){
							Display.getDefault().asyncExec(new Runnable() {
								public void run() {
									String message = "Coverage report generated successfully.";
									if (Constants.showTimes)
										message = message + generationTime;
									MessageDialog.openInformation(shell, "Coverage report", message);
									 IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
								     if (window != null) {
								    	 try {
								    	window.getActivePage().showView("AATestPlugin.coverageBrowser");
								    	BrowserView brview =  (BrowserView) window.getActivePage().findView("AATestPlugin.coverageBrowser");
								    	brview.setLocationUrl(path +"/"+ Constants.testProjectName+"/coverage/coverage.html", "Coverage report");
										window.getActivePage().showView("AATestPlugin.coverageBrowser");
										} catch (PartInitException e) {
											e.printStackTrace();
										}
								     }
								}
							});
				        }
				        else{
							Display.getDefault().asyncExec(new Runnable() {
								public void run() {
									MessageDialog.openError(shell, "Coverage report", "An errorr occured when generating coverage report. More info can be found in the logs.");
								}
							});
				        }    
			    } catch (Throwable t)
			      {
			        t.printStackTrace();
			      }

				}
			});
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	//		AATestJunitLauncher laucher = new AATestJunitLauncher();
	//		Utils.deleteCoverageFolder();
	//		Utils.createCoverageFolder();
	//		System.out.println("Delete coverage");
	//		laucher.setCoverageArgument("-javaagent:lib\\jacocoagent.jar=destfile="+Constants.coverageResourcesFolder+"\\coverage.log,append=true");
	//		laucher.launch(lastSelection, "run");
	//		 BrowserView brview = null;
			 //	 brview = 	(BrowserView) PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().showView("AATestPlugin.coverageBrowser");


		

//		Semaphore sem = new Semaphore(2);
//		JUnitCore.addTestRunListener(new Listener(sem));
//		System.out.println(list.size());
//		while (true){
//		try {
//			sem.acquire();
//		} catch (InterruptedException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
//		IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject("test");
//		
//	    StructuredSelection selection = new StructuredSelection(list);
//	    
//		JUnitLaunchShortcut launch = new JUnitLaunchShortcut();
//		launch.launch(selection, "run");
//		
//		}

	}
	
	private boolean commandLine(String command, MessageConsoleStream output, IProgressMonitor monitor ) throws InterruptedException, IOException{
		String[] cmd = new String[3];
        cmd[0] = "cmd.exe" ;
        cmd[1] = "/C" ;
        cmd[2] = command;
        Runtime rt = Runtime.getRuntime();
        Process proc = rt.exec(cmd);
        
        InputStreamReader is = new InputStreamReader(proc.getInputStream());
        BufferedReader br = new BufferedReader(is);   
        String line=null;
    	 int i =0;
		 while ( (line = br.readLine()) != null){
				i++;
		//		monitor.subTask("I'm doing something here " + i);
			    output.println("INFO> " + line); 
			//	monitor.worked(1);
			}
		  InputStreamReader isr = new InputStreamReader(proc.getErrorStream());
	      BufferedReader brr = new BufferedReader(isr);   
	      line=null;
	      int error =0;
	      while ( (line = brr.readLine()) != null){
	    	  	error++;
			    output.println("ERROR> " + line); 
				//monitor.worked(1);
		  }

         int exitVal = proc.waitFor();
         if (exitVal == 0 && error == 0)
        	 return true;
         return false;
	}
	
	
    private static MessageConsole findConsole(String name) {
	      ConsolePlugin plugin = ConsolePlugin.getDefault();
	      IConsoleManager conMan = plugin.getConsoleManager();
	      IConsole[] existing = conMan.getConsoles();
	      for (int i = 0; i < existing.length; i++)
	         if (name.equals(existing[i].getName()))
	            return (MessageConsole) existing[i];
	      //no console found, so create a new one
	      MessageConsole myConsole = new MessageConsole(name, null);
	      conMan.addConsoles(new IConsole[]{myConsole});
	      return myConsole;
  }

	public static void writeToConsole(String message) { 
		  MessageConsole myConsole = findConsole("Coverage log"); 
		  MessageConsoleStream out = myConsole.newMessageStream(); 
		  out.println(message);
		  // Make console visible 
		  IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); 
		  try { 
		    IConsoleView view = (IConsoleView) page.showView(IConsoleConstants.ID_CONSOLE_VIEW); 
		    view.display(myConsole); 
		  } catch (Exception e) { 
				e.printStackTrace(); 
		  } 
		}
	
	public void selectionChanged(IAction action, ISelection selection) {
		Utils.updateProjectsNames(selection);
		if (selection instanceof TreeSelection) {
			org.eclipse.jface.viewers.TreeSelection t = (TreeSelection) selection;
			Iterator<?> it = t.iterator();
			while (it.hasNext()) {
				Object o = it.next();
				if (o instanceof ICompilationUnit) {
					ICompilationUnit c = (ICompilationUnit) o;
					testType = "class";
					String fullName = c.getType(c.getElementName()).getFullyQualifiedName();
					objectQName = fullName.substring(0, fullName.lastIndexOf(".java"));
				} else {
					if (o instanceof IPackageFragmentRoot) {
						IPackageFragmentRoot pack = (IPackageFragmentRoot) o;
						testType = "package";
						objectQName = pack.getElementName();

					} else {
						if (o instanceof PackageFragment) {
							PackageFragment fragment = (PackageFragment) o;
							testType = "package";
							objectQName = fragment.getElementName();

						}
					}
				}
			}
		}
	}
}